package net.xuej.swfbuilder{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.JPEGEncoderOptions;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.filesystem.File;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;
	
	import org.libspark.swfassist.io.ByteArrayOutputStream;
	import org.libspark.swfassist.swf.io.SWFWriter;
	import org.libspark.swfassist.swf.io.WritingContext;
	import org.libspark.swfassist.swf.structures.FillStyle;
	import org.libspark.swfassist.swf.structures.FillStyleTypeConstants;
	import org.libspark.swfassist.swf.structures.SWF;
	import org.libspark.swfassist.swf.structures.StraightEdgeRecord;
	import org.libspark.swfassist.swf.structures.StyleChangeRecord;
	import org.libspark.swfassist.swf.tags.DefineBitsJPEG2;
	import org.libspark.swfassist.swf.tags.DefineShape;
	import org.libspark.swfassist.swf.tags.FileAttributes;
	import org.libspark.swfassist.swf.tags.PlaceObject2;
	import org.libspark.swfassist.swf.tags.RemoveObject;
	import org.libspark.swfassist.swf.tags.ShowFrame;
	import org.libspark.swfassist.swf.tags.Tag;
	import org.libspark.swfassist.swf.tags.Tags;
	
	/**
	 * swf生成器
	 * @author xuej
	 * 
	 */
	public class SWFBuilder extends EventDispatcher{
		//==========================
		// properties
		//==========================
		private static const SWF_VERSION:int = 10;
		private static const SWF_FRAME_RATE:int = 24;
		
		private var _swf:SWF;
		private var _file:File;
		private var _xml:XML;
		private var index:int = 0;
		private var linkDic:Dictionary;
		private var loaderDic:Dictionary;
		private var loadingLength:int;
		private var linkArr:Vector.<LinkInfo>;
		
		/**
		 * swf生成器
		 * 
		 */
		public function SWFBuilder(){
			_swf = initSwf();
			linkDic = new Dictionary();
			linkArr = new Vector.<LinkInfo>();
			loaderDic = new Dictionary();
		}
		
		//==========================
		// public functions
		//==========================
		/**
		 * 传入xml生成swf的ByteArray
		 * @param xml
		 * @return 
		 * 
		 */
		public function buildByXml(xml:XML):void{
			for each(var x:XML in xml.children()){
				switch(x.name().toString()){
					case EntityType.BITMAPDATA:
						loadAndCreateImgTag(x);
						break;
				}
			}
		}
		
		/**
		 * 根据目录生成swf
		 * @param dirPath
		 * 
		 */
		public function buildByDir(dirPath:String):void{
			var file:File = new File(dirPath);
			if(!file.isDirectory)return;
			var xml:XML;
			for each(var f:File in file.getDirectoryListing()){
				if(f.isDirectory)continue;
				var link:String = getLinkName(f.name);
				if(isPic(f.type)){
					xml = <{EntityType.BITMAPDATA} file={f.url} quality="80" link={link}/>;
					loadAndCreateImgTag(xml);
				}else if(isSwf(f.type)){
					//由于技术问题，先屏蔽
					continue;
					xml = <{EntityType.MOVIECLIP} file={f.url} link={link}/>;
					loadAndCreateSpriteTag(xml);
				}
			}
		}
		
		/**
		 * 新建swf
		 * @return 
		 * 
		 */
		public function initSwf(color:uint = 0xffffff):SWF{
			_swf = new SWF();
			_swf.header.version = 9;
			_swf.header.frameSize.xMax = 100;
			_swf.header.frameSize.yMax = 100;
			_swf.header.isCompressed = true;
			_swf.header.frameRate = 24;
			_swf.fileAttributes = new FileAttributes();
			_swf.fileAttributes.hasMetadata =false;
			_swf.fileAttributes.isActionScript3 = true;
			_swf.fileAttributes.useNetwork = false;
			_swf.tags = new Tags();
			var tag:Tag = null;
			tag = TagsBuilder.createBackgroundColorTag(color);
			addTag(tag);
			return _swf;
		}
		
		/**
		 * 增加tag
		 * @param tag
		 * 
		 */
		public function addTag(tag:Tag):void{
			_swf.tags.addTag(tag);
		}
		
		/**
		 * 结束
		 * 
		 */
		public function end():void{
			if(linkArr.length > 0){
				setDoABC();
				setSymbolClass();
				setShowFrame();
			}
		}
		
		/**
		 * 增加图片
		 * @param bitmapData
		 * @param quality
		 * @param className
		 * 
		 */
		public function addImg(bitmapData:BitmapData,quality:int,className:String=null,encoderType:String=ImgEncodeType.JPEG_XR):void{
			index ++;
			var tag:Tag = TagsBuilder.createImageTag(index,bitmapData,quality,encoderType);
			_swf.tags.addTag(tag);
			if(className != null)
				linkArr.push(new LinkInfo(className,EntityType.BITMAPDATA,index));
		}
		
		/**
		 * 增加原始图片
		 * @param byteArray
		 * @param className
		 * 
		 */
		public function addOriImg(byteArray:ByteArray,className:String = null):void{
			index++;
			var tag:Tag = TagsBuilder.createOriImageTag(index,byteArray);
			_swf.tags.addTag(tag);
			if(className != null)
				linkArr.push(new LinkInfo(className,EntityType.BITMAPDATA,index));
		}
		
		/**
		 * 增加帧 （单图片帧）
		 * @param bitmapData
		 * @param quality
		 * 
		 */
		public function addFrame(bmpData:BitmapData,quality:int = 80,x:int = 0,y:int = 0):void {
			var tag:Tag;
			tag = TagsBuilder.createRemoveObject(index + 2,1);
			addTag(tag);
			index ++;
			tag = TagsBuilder.createImageTag(index,bmpData,quality);			
			addTag(tag);
			var bmId:int = index;
			index ++;
			tag = TagsBuilder.createShape(index,bmId,bmpData.width,bmpData.height,x,y);
			addTag(tag);
			tag = TagsBuilder.createPlaceObject(index,1);
			addTag(tag);
			addTag(TagsBuilder.createShowFrameTag());
		}
		
		/**
		 * 增加movieclip
		 * @param byteArray swf的二进制数据
		 * @param className
		 * 
		 */
		public function addMovie(byteArray:ByteArray,className:String):void{
			index++;
			var tag:Tag = TagsBuilder.createSwfTag(index,byteArray);
			_swf.tags.addTag(tag);
				linkArr.push(new LinkInfo(className,EntityType.MOVIECLIP,index));
		}
		
		/**
		 * 获得ByteArray （保存就是swf了）
		 * @return 
		 * 
		 */
		public function getByteArray():ByteArray {
			var data:ByteArray = new ByteArray();
			var swfwriter:SWFWriter = new SWFWriter();
			var out:ByteArrayOutputStream = new ByteArrayOutputStream(data);
			var context:WritingContext = new WritingContext();
			swfwriter.writeSWF(out,context,_swf);
			return data;
		}
		
		//==========================
		// private functions
		//==========================
		private function setShowFrame():void{
			var sf:Tag = TagsBuilder.createShowFrameTag();
			addTag(sf);
		}
		
		private function setSymbolClass():void{
			var tag:Tag = TagsBuilder.createSymbolClass(linkArr);
			addTag(tag);
		}
		
		private function setDoABC():void{
			var tag:Tag = TagsBuilder.createDoABCTag(linkArr);
			addTag(tag);
		}
		
		private function loadAndCreateImgTag(x:XML):void{
			loadingLength++;
			if(x.@quality == undefined){
				loadAndCreateOriImg(x.@file.toString(),x);
			}else{
				loadAndCreateCompressImg(x.@file.toString(),x);
			}
		}
		
		private function loadAndCreateSpriteTag(x:XML):void{
			loadingLength++;
			var ul:URLLoader = new URLLoader();
			ul.dataFormat = URLLoaderDataFormat.BINARY;
			ul.addEventListener(Event.COMPLETE, onSpriteLoaded);
			ul.load(new URLRequest(x.@file.toString()));
			loaderDic[ul] = x;
		}
		
		protected function onSpriteLoaded(event:Event):void{
			var ul:URLLoader = (event.target as URLLoader);
			var xml:XML = loaderDic[ul];
			addMovie(ul.data as ByteArray,xml.@link.toString());
			delete loaderDic[ul];
			checkComplete();
		}
		
		private function loadAndCreateOriImg(path:String,info:XML=null):void{
			var ul:URLLoader = new URLLoader();
			ul.dataFormat = URLLoaderDataFormat.BINARY;
			ul.addEventListener(Event.COMPLETE, onOriImageLoaded);
			ul.load(new URLRequest(path));
			if(info!= null)
				loaderDic[ul] = info;
		}
		
		private function loadAndCreateCompressImg(path:String,info:XML=null):void{
			var l:Loader = new Loader();
			l.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded);
			l.load(new URLRequest(path));
			if(info!= null)
				loaderDic[l] = info;
		}
		
		private function onOriImageLoaded(event:Event):void{
			var ul:URLLoader = (event.target as URLLoader);
			var xml:XML = loaderDic[ul];
			addOriImg(ul.data,xml.@link.toString());
			delete loaderDic[ul];
			checkComplete();
		}
		
		private function checkComplete():void{
			loadingLength --;
			if(loadingLength == 0){
				complete();
			}			
		}
		
		private function onImageLoaded(event:Event):void{
			var xml:XML = loaderDic[(event.target as LoaderInfo).loader];
			var bmd:BitmapData = (((event.target as LoaderInfo).content as Bitmap).bitmapData);
			var type:String = ImgEncodeType.JPEG;
			if(xml.@type != undefined){
				type = xml.@type.toString();
			}
			addImg(bmd,int(xml.@quality),xml.@link.toString(),type);
			
			delete loaderDic[(event.target as LoaderInfo).loader];
			(event.target as LoaderInfo).removeEventListener(Event.COMPLETE,onImageLoaded);
			(event.target as LoaderInfo).loader.unload();
			checkComplete();			
		}
		
		private function complete():void{
			end();
			this.dispatchEvent(new Event(Event.COMPLETE));			
		}
		
		private function isPic(type:String):Boolean{
			if(type == null)return false;
			type = type.toLocaleLowerCase();
			switch(type) {
				case ".jpg":
				case ".jpeg":
				case ".gif":
				case ".png":
					return true;
			}
			return false;
		}
		
		private function isSwf(type:String):Boolean{
			if(type == null)return false;
			type = type.toLocaleLowerCase();
			switch(type) {
				case ".swf":
					return true;
			}
			return false;
		}
		
		private function getLinkName(name:String):String{
			if(name.lastIndexOf(".") == -1)return name;
			return name.substring(0,name.lastIndexOf("."))
		}
	}
}